package org.simpleframework.core;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.annotation.Component;
import org.simpleframework.core.annotation.Controller;
import org.simpleframework.core.annotation.Repository;
import org.simpleframework.core.annotation.Service;
import org.simpleframework.util.ClassUtil;
import org.simpleframework.util.ValidationUtil;

/**
 * @Author: yu.zhou
 * @DateTime: 2023/01/04 14:36 bean的容器
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {

    /**
     * 存放所有被配置标记的目标对象
     */
    private static final Map<Class<?>, Object> beanMap = new ConcurrentHashMap();

    /**
     * 加载bean的注册列表
     */
    private static final List<Class<? extends Annotation>> BEAN_ANNOTATION = Arrays
            .asList(Component.class, Controller.class, Repository.class, Service.class);

    /**
     * 安全饿汉单例模式持有容器实例
     */
    private enum ContainHolder {
        /**
         * 枚举持有实例
         */
        HOLDER;
        private final BeanContainer instance;

        ContainHolder() {
            instance = new BeanContainer();
        }
    }

    /**
     * 容器是否被加载的标识bean
     */
    private boolean loaded = false;

    /**
     * 获取容器是否被加载的标识
     */
    public boolean isLoaded() {
        return loaded;
    }

    /**
     * 获取beanContainer的实例
     *
     * @return
     */
    public static BeanContainer getInstance() {
        return ContainHolder.HOLDER.instance;
    }

    /**
     * 扫描加载所有的bean对象
     *
     * @param basePackage
     */
    public synchronized void loadBeans(String basePackage) {
        if (isLoaded()) {
            log.warn("beanContain has been loaded..");
            return;
        }
        Set<Class<?>> classSet = ClassUtil.extractPageClass(basePackage);
        if (ValidationUtil.isEmpty(classSet)) {
            log.warn("extract nothing from packageName " + basePackage);
            return;
        }
        for (Class<?> clazz : classSet) {
            for (Class<? extends Annotation> annotation : BEAN_ANNOTATION) {
                // 循环clazz是否被标注了annotation注解
                if (clazz.isAnnotationPresent(annotation)) {
                    beanMap.put(clazz, ClassUtil.newInstance(clazz, true));
                }
            }
        }
        loaded = true;
    }

    /**
     * 获取容器中的bean的数量
     *
     * @return
     */
    public int getBeanCount() {
        return beanMap.size();
    }

    /**
     * 添加元素
     *
     * @param clazz 字节码对象
     * @param bean  Object实例
     * @return 添加成功的对象实例
     */
    public Object addBean(Class<?> clazz, Object bean) {
        return beanMap.put(clazz, bean);
    }

    /**
     * 删除容器元素
     *
     * @param clazz 字节码对象
     * @return 返回删除的对象实例
     */
    public Object removeBean(Class<?> clazz) {
        return beanMap.remove(clazz);
    }

    /**
     * 根据class对象获取bean实例
     *
     * @param clazz 字节码对象 .class
     * @return 容器中class对象对应的bean实例
     */
    public Object getBean(Class<?> clazz) {
        return beanMap.get(clazz);
    }

    /**
     * 获取beanMap内的所有class对象集合
     *
     * @return beanMap的key
     */
    public Set<Class<?>> getClasses() {
        return beanMap.keySet();
    }

    /**
     * 返回beanMap种的所有Object对象
     *
     * @return beanMap的value
     */
    public Set<Object> getBeans() {
        return new HashSet<>(beanMap.values());
    }

    /**
     * 获取被某一注解标识的字节码对象集合
     *
     * @param annotation 需要查询的特定的注解
     * @return 返回一个字节码对象的set集合容器内为空就返回null
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation) {
        HashSet<Class<?>> classHashSet = new HashSet<>();
        beanMap.keySet().stream().filter(Objects::nonNull)
                .forEach(clazz -> {
                    if (clazz.isAnnotationPresent(annotation)) {
                        classHashSet.add(clazz);
                    }
                });
        return classHashSet.size() > 0 ? classHashSet : null;
    }

    /**
     * 返回某一个接口或者父类的子类
     *
     * @param interfaceOrClass 需要返回子类的接口或者父类
     * @return 容器内为空返回null ,否则返回子类
     */
    public Set<Class<?>> getClassBySuper(Class<?> interfaceOrClass) {
        Set<Class<?>> keySet = getClasses();
        if (ValidationUtil.isEmpty(keySet)) {
            log.warn("nothing in beanMap");
            return null;
        }
        // 2.判断keySet里的元素是否传入
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> clazz : keySet) {
            if (interfaceOrClass.isAssignableFrom(clazz)) {
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0 ? classSet : null;
    }


}
